package com.atguigu.gmall.order.controller;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.activity.client.ActivityFeignClient;
import com.atguigu.gmall.cart.client.CartFeignClient;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderDetailVo;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.model.order.OrderTradeVo;
import com.atguigu.gmall.model.user.UserAddress;
import com.atguigu.gmall.order.config.ThreadPoolConfig;
import com.atguigu.gmall.order.service.OrderService;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.atguigu.gmall.user.client.UserFeignClient;
import com.sun.org.apache.regexp.internal.RE;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.filter.OrderedFilter;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author ：Shine
 * @description：
 * @date ：2021/3/3 10:49
 */
@RestController
@RequestMapping("api/order")
public class OrderApiController {
    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private CartFeignClient cartFeignClient;

    @Autowired
    private OrderService orderService;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private ActivityFeignClient activityFeignClient;

    @GetMapping("auth/trade")
    public Result<Map<String, Object>> trade(HttpServletRequest request) {
        // 获取到用户Id
        String userId = AuthContextHolder.getUserId(request);

        //获取用户地址
        List<UserAddress> userAddressList = userFeignClient.findUserAddressListByUserId(userId);

        // 渲染送货清单
        // 先得到用户想要购买的商品！
        List<CartInfo> cartInfoList = cartFeignClient.getCartCheckedList(userId);
        // 声明一个集合来存储订单明细
        ArrayList<OrderDetail> detailArrayList = new ArrayList<>();
        for (CartInfo cartInfo : cartInfoList) {
            OrderDetail orderDetail = new OrderDetail();

            orderDetail.setSkuId(cartInfo.getSkuId());
            orderDetail.setSkuName(cartInfo.getSkuName());
            orderDetail.setImgUrl(cartInfo.getImgUrl());
            orderDetail.setSkuNum(cartInfo.getSkuNum());
            orderDetail.setOrderPrice(cartInfo.getCartPrice());

            // 添加到集合
            detailArrayList.add(orderDetail);
        }

        //获取购物车满足条件的促销与优惠券信息
        OrderTradeVo orderTradeVo = activityFeignClient.findTradeActivityAndCoupon(detailArrayList, Long.parseLong(userId));
        List<OrderDetailVo> orderDetailVoList = null;
        BigDecimal activityReduceAmount = new BigDecimal("0");

        orderDetailVoList = orderTradeVo.getOrderDetailVoList();
        activityReduceAmount = orderTradeVo.getActivityReduceAmount();


        // 计算总金额
        // 计算总金额
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderDetailList(detailArrayList);
        orderInfo.setActivityReduceAmount(activityReduceAmount);
        orderInfo.sumTotalAmount();

        Map<String, Object> result = new HashMap<>();
        result.put("userAddressList", userAddressList);
        result.put("detailArrayList", detailArrayList);
        // 保存总金额
        result.put("totalNum", detailArrayList.size());
        result.put("totalAmount", orderInfo.getTotalAmount());
        result.put("activityReduceAmount", orderInfo.getActivityReduceAmount());
        result.put("originalTotalAmount", orderInfo.getOriginalTotalAmount());
        result.put("orderDetailVoList", orderDetailVoList);

        // 获取流水号
        String tradeNo = orderService.getTradeNo(userId);
        result.put("tradeNo", tradeNo);

        result.put("couponInfoList", orderTradeVo.getCouponInfoList());

        return Result.ok(result);

    }

    @PostMapping("auth/submitOrder")
    public Result submitOrder(@RequestBody OrderInfo orderInfo, HttpServletRequest request) {
        //要将前端穿过来的json对象转换为java对象要使用@requestBod注解
        String userId = AuthContextHolder.getUserId(request);
        orderInfo.setUserId(Long.parseLong(userId));

        //获取页面传递的流水号
        String tradeNo = request.getParameter("tradeNo");
        boolean flag = orderService.checkTradeNo(tradeNo, userId);
        if (!flag) {
            return Result.fail().message("不能重复提交订单");
        }

        //创建一个字符串集合，用来存储提示信息
        ArrayList<String> errorList = new ArrayList<>();

        //创建一个集合来存储异步编排对象
        ArrayList<CompletableFuture> completableFutureArrayList = new ArrayList<>();

        //验证库存
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if (!CollectionUtils.isEmpty(orderDetailList)) {
            for (OrderDetail orderDetail : orderDetailList) {
                CompletableFuture<Void> checkStockCompletableFuture = CompletableFuture.runAsync(() -> {
                    boolean result = orderService.checkStock(orderDetail.getSkuId(), orderDetail.getSkuNum());
                    if (!result) {
                        // return Result.fail().message(orderDetail.getSkuName() + "库存不足");
                        errorList.add(orderDetail.getSkuName() + "库存不足");
                    }
                }, threadPoolExecutor);
                completableFutureArrayList.add(checkStockCompletableFuture);

                CompletableFuture<Void> skuPriceCompletableFuture = CompletableFuture.runAsync(() -> {
                    //  再次验证实时价格，防止价格出错
                    BigDecimal skuPrice = productFeignClient.getSkuPrice(orderDetail.getSkuId());
                    if (orderDetail.getOrderPrice().compareTo(skuPrice) != 0) {
                        //更新购物车价格
                        cartFeignClient.loadCartCache(userId);
                        //给用户提示
                        // return Result.fail().message(orderDetail.getSkuName() + "价格有变动!");
                        errorList.add(orderDetail.getSkuName() + "价格有变动!");
                    }
                }, threadPoolExecutor);
                completableFutureArrayList.add(skuPriceCompletableFuture);
            }
        }

        //使用allOf将多线程任务组装到一起
        CompletableFuture.allOf(completableFutureArrayList.toArray(new CompletableFuture[completableFutureArrayList.size()])).join();

        //判断是否有变动数据
        if (errorList.size() > 0) {
            return Result.fail().message(StringUtils.join(errorList, ","));
        }

        //删除缓存的流水号
        orderService.deleteTradeNo(userId);
        Long orderId = orderService.saveOrderInfo(orderInfo);

        //发送延迟消息,发送的消息与处理的业务有关
        rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL, MqConst.ROUTING_ORDER_CANCEL, orderId, MqConst.DELAY_TIME);
        return Result.ok(orderId);
    }

    @GetMapping("inner/getOrderInfo/{orderId}")
    public OrderInfo getOrderInfo(@PathVariable Long orderId) {
        return orderService.getOrderInfo(orderId);
    }

    @RequestMapping("orderSplit")
    public String orderSplit(HttpServletRequest request) {
        String orderId = request.getParameter("orderId");
        String wareSkuMap = request.getParameter("wareSkuMap");

        //拆单方法，返回子订单的json字符串
        List<OrderInfo> subOrderInfoList = orderService.orderSplit(Long.parseLong(orderId), wareSkuMap);
        ArrayList<Map> mapArrayList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(subOrderInfoList)) {
            for (OrderInfo orderInfo : subOrderInfoList) {
                Map map = orderService.initWareOrder(orderInfo);
                mapArrayList.add(map);
            }
        }
        return JSON.toJSONString(mapArrayList);
    }

    @PostMapping("inner/seckill/submitOrder")
    public Long submitOrder(@RequestBody OrderInfo orderInfo) {
        return orderService.saveOrderInfo(orderInfo);
    }

}
